package com.group.sliding.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group.sliding.context.UserContext;
import com.group.sliding.domain.dto.PayOrderFormDTO;
import com.group.sliding.domain.po.Order;
import com.group.sliding.domain.po.PayOrder;
import com.group.sliding.domain.query.PayOrderPageQuery;
import com.group.sliding.domain.vo.PayOrderVO;
import com.group.sliding.enums.PayStatus;
import com.group.sliding.exception.BizIllegalException;
import com.group.sliding.mapper.OrderMapper;
import com.group.sliding.mapper.PayOrderMapper;
import com.group.sliding.service.IOrderService;
import com.group.sliding.service.IPayOrderService;
import com.group.sliding.service.IUserService;
import com.group.sliding.utils.BeanUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 支付订单 服务实现类
 * </p>
 */
@Service
@RequiredArgsConstructor
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {

    private final IUserService userService;
    private final IOrderService orderService;

    private final OrderMapper orderMapper;

    @Override
    public PayOrder createPayOrder(Long orderId) {
        // 幂等性校验
        return checkIdempotent(orderId);
    }

    @Override
    @Transactional
    public void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO) {
        // 查询支付单
        PayOrder po = getById(payOrderFormDTO.getId());
        // 合法性判断
        checkLegal(po);
        // 判断状态
        if (!PayStatus.WAIT_BUYER_PAY.equals(po.getStatus())) {
            // 订单不是未支付，状态异常
            throw new BizIllegalException("交易已支付或关闭！");
        }
        // 尝试扣减余额
        userService.deductMoney(payOrderFormDTO.getPassword(), po.getAmount());
        // 修改支付单状态
        boolean success = markPayOrderSuccess(payOrderFormDTO.getId(), LocalDateTime.now());
        if (!success) {
            throw new BizIllegalException("交易已支付或关闭！");
        }
        // 修改订单状态
        orderService.markOrderPaySuccess(po.getOrderId());
    }

    private void checkLegal(PayOrder po) {
        if (po == null) {
            throw new BizIllegalException("支付订单不存在");
        }
        if (!UserContext.getUser().equals(po.getUserId())) {
            throw new BizIllegalException("非自己的支付订单");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPayOrder(Long id) {
        // 查询支付单
        PayOrder po = getById(id);
        // 合法性判断
        checkLegal(po);
        // 取消支付订单
        if (PayStatus.TRADE_FINISHED.equals(po.getStatus())) {
            throw new BizIllegalException("订单已完成");
        }
        po.setStatus(PayStatus.TRADE_CLOSED);
        po.setUpdateTime(LocalDateTime.now());
        updateById(po);
        // 订单状态也要改为取消
        orderService.cancelOrder(po.getOrderId());
    }

    @Override
    public Page<PayOrder> search(PayOrderPageQuery query) {
        return lambdaQuery()
                .eq(query.getId() != null, PayOrder::getId, query.getId())
                .eq(query.getOrderId() != null, PayOrder::getOrderId, query.getOrderId())
                .eq(query.getUserId() != null, PayOrder::getUserId, query.getUserId())
                .page(query.toMpPage("update_time", false));
    }

    @Override
    public List<PayOrderVO> queryMyPayOrders() {
        QueryWrapper<PayOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PayOrder::getUserId, UserContext.getUser());
        List<PayOrder> list = list(queryWrapper);
        return BeanUtils.copyList(list, PayOrderVO.class);
    }

    public boolean markPayOrderSuccess(Long id, LocalDateTime successTime) {
        return lambdaUpdate()
                .set(PayOrder::getStatus, PayStatus.TRADE_FINISHED.getValue())
                .set(PayOrder::getUpdateTime, successTime)
                .eq(PayOrder::getId, id)
                // 支付状态的乐观锁判断
                .in(PayOrder::getStatus, PayStatus.NOT_COMMIT.getValue(), PayStatus.WAIT_BUYER_PAY.getValue())
                .update();
    }


    private PayOrder checkIdempotent(Long orderId) {
        PayOrder oldOrder = lambdaQuery()
                .eq(PayOrder::getOrderId, orderId)
                .one();
        // 判断是否存在
        if (oldOrder == null) {
            // 不存在支付单，说明是第一次，写入新的支付单并返回
            PayOrder payOrder = buildPayOrder(orderId);
            payOrder.setId(IdWorker.getId());
            save(payOrder);
            return payOrder;
        }
        // 判断是否支付成功
        if (PayStatus.TRADE_FINISHED.equals(oldOrder.getStatus())) {
            // 已经支付成功，抛出异常
            throw new BizIllegalException("订单已经支付！");
        }
        // 判断是否已经关闭
        if (PayStatus.TRADE_CLOSED.equals(oldOrder.getStatus())) {
            // 已经关闭，抛出异常
            throw new BizIllegalException("订单已关闭");
        }
        // 旧单已经存在，可能是未支付或未提交，直接返回旧数据
        throw new BizIllegalException("订单已经生成过了，请前往支付");
    }

    private PayOrder buildPayOrder(Long orderId) {
        // 查找订单，找到总额
        Order order = orderMapper.selectById(orderId);
        PayOrder payOrder = new PayOrder();
        payOrder.setUserId(UserContext.getUser());
        payOrder.setOrderId(orderId);
        payOrder.setAmount(order.getTotalFee());
        payOrder.setStatus(PayStatus.WAIT_BUYER_PAY);
        LocalDateTime now = LocalDateTime.now();
        payOrder.setCreateTime(now);
        payOrder.setUpdateTime(now);
        return payOrder;
    }
}
